﻿using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using NetCore.Model;
using NetCore.WS;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace NetCore.BLL
{

    /// <summary>
    /// WebSocket
    /// </summary>
    public class WebSocketHelper
    {
        private static ConcurrentDictionary<string, UserSocket> _socketConnectUsers;
        private INotifyService _service = null;

        public INotifyService notifyService { get {
                if (_service == null)
                {
                    _service = AppHttpContext.GetSerivce<INotifyService>();
                }
                return _service;
            } }
        /// <summary>
        /// 用于存储在线的websocket用户
        /// </summary>
        public static ConcurrentDictionary<string, UserSocket> SocketConnectUsers
        {
            get {
               
                return _socketConnectUsers;
            }
        }
        public const int BufferSize = 4096;
        UserSocket _uSocket;
        public WebSocketHelper(WebSocket socket)
        {
            _uSocket = new UserSocket();
            _uSocket.Socket = socket;
        }
        async Task EchoLoop()
        {
            var buffer = new byte[1024 * 4];
            WebSocketReceiveResult result = await _uSocket.Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            if (_socketConnectUsers == null)
            {
                _socketConnectUsers = new ConcurrentDictionary<string, UserSocket>();
            }
            if (_uSocket == null)
            {
                _uSocket= new UserSocket();
            }
            #region 创建websocket Id
            if (string.IsNullOrWhiteSpace(ApplicationEnvironments.DefaultSession.UserId))
            {
                _uSocket.UserName= _uSocket.UserId = MyGenerateHelper.GenerateOrder();
               
            }
            else
            {
                _uSocket.UserName = _uSocket.UserId = ApplicationEnvironments.DefaultSession.UserId;
                if (!string.IsNullOrWhiteSpace(ApplicationEnvironments.DefaultSession.UserId))
                {
                    _uSocket.UserName = ApplicationEnvironments.DefaultSession.GetUser<UserEntity>().RealName;
                }
               
            }
            #endregion
            if (!result.CloseStatus.HasValue)//第一次连接 
            {
                _socketConnectUsers.TryAdd(_uSocket.UserId, _uSocket);
                await SendAsync(new WSMessageHelper {//连接成功时返回用户id
                    SenderId="Service",
                    SenderName="系统",
                    ReceiverId= _uSocket.UserId,
                     MessageType="text",
                     Content="open"
                }, WebSocketMessageType.Text, result.EndOfMessage);
            }
            while (!result.CloseStatus.HasValue)
            {
                string sendMsg= ReceiveString(buffer,result);
                WSMessageHelper wSMessage = null;
                if (!string.IsNullOrWhiteSpace(sendMsg))
                {
                    wSMessage= JSONHelper.FromJson<WSMessageHelper>(sendMsg);
                }
                if (wSMessage != null&&!string.IsNullOrWhiteSpace(wSMessage.ReceiverId)&& !wSMessage.ReceiverId.ToLower().Equals("service"))
                {
                    wSMessage.SenderName = _uSocket.UserName;

                    if (!await SendAsync(wSMessage, WebSocketMessageType.Text, true))//false表示发送失败
                    {
                        string strError = "";
                        try
                        {
                            notifyService.Send(_uSocket.UserId, wSMessage.ReceiverId,"",NotifyTypeEnum.Users,  "留言", wSMessage.Content.ToString(), ref strError);
                        }
                        catch (Exception ex)
                        {
                            strError = ex.Message;
                        }
                       await SendAsync(new WSMessageHelper //，失败时回发用户消息
                       {
                            SenderId = "Service",
                            ReceiverId = _uSocket.UserId,
                           SenderName="系统",
                            MessageType = "text",
                            Content = "用户已下线，消息改为留言"+ strError
                       }, WebSocketMessageType.Text, result.EndOfMessage);
                    }
                }
                result = await _uSocket.Socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
            }
            _socketConnectUsers.TryRemove(_uSocket.UserId, out _uSocket);
            await _uSocket.Socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="message">消息对象</param>
        /// <param name="messageType">消息类型</param>
        /// <param name="endOfMessage">是否结束消息</param>
        /// <returns></returns>
        public async Task<bool> SendAsync(WSMessageHelper message, WebSocketMessageType messageType, bool endOfMessage)
        {
            var buffer1 = FileHelper.StringToByte("utf-8", JSONHelper.ToJson(message));
            var outgoing = new ArraySegment<byte>(buffer1, 0, buffer1.Length);
            UserSocket usocket = null;
            if (_socketConnectUsers.TryGetValue(message.ReceiverId, out usocket))
            {
                await usocket.Socket.SendAsync(outgoing, messageType, endOfMessage, CancellationToken.None);
                return true;
            }
            return false;
          
        }

        private string ReceiveString(ArraySegment<byte> buffer,WebSocketReceiveResult result)
        {
            using (var ms = new MemoryStream())
            {
                do
                {
                    ms.Write(buffer.Array, buffer.Offset, result.Count);
                }
                while (!result.EndOfMessage);

                ms.Seek(0, SeekOrigin.Begin);
                if (result.MessageType != WebSocketMessageType.Text)
                {
                    return null;
                }

                using (var reader = new StreamReader(ms, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }
        static async Task Acceptor(HttpContext hc, Func<Task> n)
        {
            if (!hc.WebSockets.IsWebSocketRequest)
                return;
            var socket = await hc.WebSockets.AcceptWebSocketAsync();
            var h = new WebSocketHelper(socket);
            await h.EchoLoop();
        }
        /// <summary>
        /// 路由绑定处理
        /// </summary>
        /// <param name="app"></param>
        public static void Map(IApplicationBuilder app)
        {
            app.UseWebSockets();
            app.Use(WebSocketHelper.Acceptor);
        }
    }
}

